package cn.xioabai.common.utility;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.poi.excel.ExcelFileUtil;
import cn.xioabai.common.constant.JsonStrConstant;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author yangdaji
 * @Date 2022/11/3 0003
 * @PackageName cn.xioabai.utils
 * @ClassName IOUtils
 */

public class IOUtils {

    private static Logger log = LoggerFactory.getLogger(IOUtils.class);

    /**
     * 读取文件内容为字符串
     *
     * @param file 文件
     * @return
     */
    public static String readFileToString(File file) {

        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            return readInputStreamToString(fileInputStream);
        } catch (Exception e) {
            log.error("读取文件失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从输入流中读取数据为字符串
     *
     * @param inputStream 输入流
     * @return
     */
    public static String readInputStreamToString(InputStream inputStream) {
        return IoUtil.read(inputStream, "UTF-8");
    }

    /**
     * 将字符串数据写入指定位置的文件中
     *
     * @param data     字符串数据
     * @param path     文件位置
     * @param fileName 文件名称
     */
    public static Boolean wireStringToFile(String data, String path, String fileName) {
        path = path.replace("\\", "/") + "/";
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }

        path = path + fileName;
        try {
            IoUtil.write(new FileOutputStream(path), "UTF-8", true, data);
        } catch (FileNotFoundException e) {
            log.error("写入文件失败: {}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 将数据写入文件, 并保存在当前目录
     *
     * @param data     数据
     * @param fileName 文件
     */
    public static void dataWriteFile(String data, String fileName) {
        File file = Paths.get(fileName).getParent().toFile();
        if (!file.exists()) {
            file.mkdirs();
        }
        try (FileWriter fw = new FileWriter(fileName);
             BufferedWriter br = new BufferedWriter(fw)) {
            br.write(data);
            br.flush();
            log.info("保存 {} 文件完成", fileName);
        } catch (IOException e) {
            log.error("写入文件失败: {}", e.getMessage());
        }
    }

    /**
     * 读取当前目录的文件
     *
     * @param fileName 文件名称
     * @return
     */
    public static String readerFileToString(String fileName) {

        try (FileReader fw = new FileReader(fileName);
             BufferedReader br = new BufferedReader(fw)) {

            StringBuilder stringBuffer = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                stringBuffer.append(line);
                stringBuffer.append("\n");
            }
            return stringBuffer.toString();
        } catch (IOException e) {
            log.error("读取文件失败: {}", e.getMessage());
            return null;
        }
    }


    /**
     * 获取文件名称, 不包含后缀名
     *
     * @param file 文件
     * @return
     */
    public static String getFileName(File file) {
        String filePathName = file.getName();
        String suffix = JsonStrConstant.JSON_SUFFIX;
        if (filePathName.contains(suffix)) {
            return filePathName.split(suffix)[0];
        }
        return null;
    }

    /**
     * 获取文件名称,不包含后缀名
     *
     * @param file 文件
     * @return
     */
    public static String getFileBaseName(File file) {
        return FilenameUtils.getBaseName(file.getName());
    }

    /**
     * 获取文件后缀名
     *
     * @param file 文件
     * @return
     */
    public static String getFileExtension(File file) {
        return FilenameUtils.getExtension(file.getName());
    }

    /**
     * 通过文件路径获取文件后缀名
     *
     * @param path 文件路径
     * @return
     */
    public static String getFileExtension(String path) {
        String fileName = Paths.get(path).toFile().getName();
        return FilenameUtils.getExtension(fileName);
    }

    /**
     * 扫描该目录下指定后缀的文件
     *
     * @param path   目录
     * @param suffix 后缀名
     * @return
     */
    public static List<File> scanFilePath(String path, String suffix) {
        //所有文件
        List<File> fileList = new LinkedList<>();
        if (StringUtils.isBlank(path)) {
            return fileList;
        }
        recursionFileToSuffix(Paths.get(path).toFile().listFiles()
                , fileList, suffix);
        return fileList;
    }

    /**
     * 限制性的扫描该目录下指定后缀的文件,当前目录超过指定数量后将不列入扫描范围
     *
     * @param path   目录
     * @param suffix 后缀名
     * @return
     */
    public static List<File> scanFilePathLimit(String path, String suffix, Integer number) {
        /*
            先处理一个目录下所有文件, 将非目录的文件提取, 以索引进行存储
         */
        //所有文件
        List<File> fileList = new LinkedList<>();
        if (StringUtils.isBlank(path)) {
            return fileList;
        }
        recursionFileToSuffixLimit(Paths.get(path).toFile().listFiles()
                , fileList, suffix, number);
        return fileList;
    }

    /**
     * 递归所有目录下所有文件以路径列表展示
     *
     * @param files     文件列表
     * @param filePaths 文件路径列表
     * @return
     */
    public static List<String> recursionFilePaths(File[] files, List<String> filePaths) {

        if (ArrayUtil.isEmpty(files)) {
            return filePaths;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                recursionFilePaths(file.listFiles(), filePaths);
            } else if (file.isFile()) {
                filePaths.add(file.getAbsolutePath());
            }
        }
        return filePaths;
    }

    /**
     * 递归所有目录下所有文件以文件对象展示
     *
     * @param files     文件列表
     * @param filePaths 文件路径列表
     * @return
     */
    public static List<File> recursionFile(File[] files, List<File> filePaths) {

        if (ArrayUtil.isEmpty(files)) {
            return filePaths;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                recursionFile(file.listFiles(), filePaths);
            } else if (file.isFile()) {
                filePaths.add(file);
            }
        }
        return filePaths;
    }

    /**
     * 递归所有目录下所有文件符合指定后缀的文件
     *
     * @param files     文件列表
     * @param filePaths 文件路径列表
     * @param suffix    后缀名
     * @return
     */
    public static List<File> recursionFileToSuffix(File[] files, List<File> filePaths, String suffix) {

        if (ArrayUtil.isEmpty(files)) {
            return filePaths;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                recursionFileToSuffix(file.listFiles(), filePaths, suffix);
            } else if (file.isFile()) {
                // 只添加指定后缀的文件
                if (file.getName().endsWith(suffix)) {
                    filePaths.add(file);
                }
            }
        }
        return filePaths;
    }

    /**
     * 限制性递归所有符合指定后缀的文件
     *
     * @param files     文件列表
     * @param filePaths 文件路径列表
     * @param suffix    后缀名
     * @param number    数量
     * @return
     */
    public static List<File> recursionFileToSuffixLimit(File[] files, List<File> filePaths,
                                                        String suffix, Integer number) {
        AtomicInteger fileNumberCount = new AtomicInteger();
        if (ArrayUtil.isEmpty(files)) {
            return filePaths;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                recursionFileToSuffixLimit(file.listFiles(), filePaths, suffix, number);
            } else if (file.isFile()) {
                // 只添加指定后缀的文件
                if (file.getName().endsWith(suffix) &&
                        !number.equals(fileNumberCount.get())) {
                    fileNumberCount.addAndGet(1);
                    filePaths.add(file);
                }
            }
        }
        return filePaths;
    }


    //=========== 判断文件类型

    /**
     * 判断文件类型 (xls)
     *
     * @param file 文件
     * @return
     */
    public static boolean isXls(File file) {
        try {
            return ExcelFileUtil.isXlsx(file);
        } catch (Exception e) {
            log.error("判断文件异常: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 判断文件类型 (xlsx)
     *
     * @param file 文件
     * @return
     */
    public static boolean isXlsx(File file) {
        try {
            return ExcelFileUtil.isXlsx(new FileInputStream(file));
        } catch (IORuntimeException | FileNotFoundException e) {
            log.error("判断文件异常: {}", e.getMessage());
            return false;
        }
    }

}
